Skip to content

Conversation

@redstar
Copy link
Member

@redstar redstar commented Nov 26, 2025

The Language Environment (LE) reserves 128 byte for the argument area when the optional field is not present. If the argument area is larger, then the field must be present to guarantee that the space is reseverd on stack
extension. Creating this field when alloca() is used may reduce the needed stack space in case alloca() causes a stack extension.

The Language Environment (LE) reserves 128 byte for the
argument area when the optional field is not present. If
the argument area is larger, then the field must be present
to guarantee that the space is reseverd on stack
extension. Creating this field when alloca() is used may
reduce the needed stack space in case alloca() causes a
stack extension.
@redstar redstar requested a review from uweigand November 26, 2025 17:03
@redstar redstar self-assigned this Nov 26, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 26, 2025

@llvm/pr-subscribers-backend-systemz

Author: Kai Nacke (redstar)

Changes

The Language Environment (LE) reserves 128 byte for the argument area when the optional field is not present. If the argument area is larger, then the field must be present to guarantee that the space is reseverd on stack
extension. Creating this field when alloca() is used may reduce the needed stack space in case alloca() causes a stack extension.


Full diff: https://github.com/llvm/llvm-project/pull/169679.diff

2 Files Affected:

  • (modified) llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp (+30-3)
  • (added) llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll (+66)
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index e31d7c6a86476..f6dd60fa8b199 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1270,7 +1270,7 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() {
 
 static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
                           bool StackProtector, bool FPRMask, bool VRMask,
-                          bool EHBlock, bool HasName) {
+                          bool EHBlock, bool HasArgAreaLength, bool HasName) {
   enum class PPA1Flag1 : uint8_t {
     DSA64Bit = (0x80 >> 0),
     VarArg = (0x80 >> 7),
@@ -1282,8 +1282,9 @@ static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
     LLVM_MARK_AS_BITMASK_ENUM(ExternalProcedure)
   };
   enum class PPA1Flag3 : uint8_t {
+    HasArgAreaLength = (0x80 >> 1),
     FPRMask = (0x80 >> 2),
-    LLVM_MARK_AS_BITMASK_ENUM(FPRMask)
+    LLVM_MARK_AS_BITMASK_ENUM(HasArgAreaLength)
   };
   enum class PPA1Flag4 : uint8_t {
     EPMOffsetPresent = (0x80 >> 0),
@@ -1307,6 +1308,9 @@ static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
   if (StackProtector)
     Flags2 |= PPA1Flag2::STACKPROTECTOR;
 
+  if (HasArgAreaLength)
+    Flags3 |= PPA1Flag3::HasArgAreaLength; // Add emit ArgAreaLength flag.
+
   // SavedGPRMask, SavedFPRMask, and SavedVRMask are precomputed in.
   if (FPRMask)
     Flags3 |= PPA1Flag3::FPRMask; // Add emit FPR mask flag.
@@ -1339,6 +1343,10 @@ static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg,
   OutStreamer->emitInt8(static_cast<uint8_t>(Flags2)); // Flags 2.
 
   OutStreamer->AddComment("PPA1 Flags 3");
+  if ((Flags3 & PPA1Flag3::HasArgAreaLength) ==
+      PPA1Flag3::HasArgAreaLength)
+    OutStreamer->AddComment(
+        "  Bit 1: 1 = Argument Area Length is in optional area");
   if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask)
     OutStreamer->AddComment("  Bit 2: 1 = FP Reg Mask is in optional area");
   OutStreamer->emitInt8(
@@ -1477,12 +1485,26 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
 
   bool NeedEmitEHBlock = !MF->getLandingPads().empty();
 
+  // Optional Argument Area Length.
+  // Note: This represents the length of the argument area that we reserve
+  //       in our stack for setting up arguments for calls to other
+  //       routines. If this optional field is not set, LE will reserve
+  //       128 bytes for the argument area. This optional field is
+  //       created if greater than 128 bytes is required - to guarantee
+  //       the required space is reserved on stack extension in the new
+  //       extension.  This optional field is also created if the
+  //       routine has alloca(). This may reduce stack space
+  //       if alloca() call causes a stack extension.
+  bool HasArgAreaLength =
+      (AllocaReg != 0) || (MFFrame.getMaxCallFrameSize() > 128);
+
   bool HasName =
       MF->getFunction().hasName() && MF->getFunction().getName().size() > 0;
 
   emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(),
                 MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0,
-                TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock, HasName);
+                TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock,
+                HasArgAreaLength, HasName);
 
   OutStreamer->AddComment("Length/4 of Parms");
   OutStreamer->emitInt16(
@@ -1490,6 +1512,11 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
   OutStreamer->AddComment("Length of Code");
   OutStreamer->emitAbsoluteSymbolDiff(FnEndSym, CurrentFnEPMarkerSym, 4);
 
+  if (HasArgAreaLength) {
+    OutStreamer->AddComment("Argument Area Length");
+    OutStreamer->emitInt32(MFFrame.getMaxCallFrameSize());
+  }
+
   // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3).
   if (SavedFPRMask) {
     OutStreamer->AddComment("FPR mask");
diff --git a/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll b/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll
new file mode 100644
index 0000000000000..511bc46567607
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll
@@ -0,0 +1,66 @@
+; RUN: llc < %s -mtriple=s390x-ibm-zos -emit-gnuas-syntax-on-zos=0 | FileCheck %s
+%struct.LargeStruct_t = type { [33 x i32] }
+
+@GlobLargeS = hidden global %struct.LargeStruct_t zeroinitializer, align 4
+@GlobInt = hidden global i32 0, align 4
+
+; === Check that function with small frame does not emit PPA1 Argument Area Length.
+define void @fSmallOutArgArea() {
+; CHECK-LABEL: L#EPM_fSmallOutArgArea_0 DS 0H
+; CHECK: *   Bit 1: 1 = Leaf function
+; CHECK: *   Bit 2: 0 = Does not use alloca
+; CHECK:  DC XL4'00000008'
+; CHECK: fSmallOutArgArea DS 0H
+; CHECK: L#PPA1_fSmallOutArgArea_0 DS 0H
+; CHECK: * PPA1 Flags 3
+; CHECK:  DC XL1'00'
+  ret void
+}
+
+; === Check that function with large frame does emit PPA1 Argument Area Length.
+define void @fLargeOutArgArea() {
+; CHECK-LABEL: L#EPM_fLargeOutArgArea_0 DS 0H
+; CHECK: *   Bit 1: 0 = Non-leaf function
+; CHECK: *   Bit 2: 0 = Does not use alloca
+; CHECK:  DC XL4'00000220'
+; CHECK: fLargeOutArgArea DS 0H
+; CHECK: L#PPA1_fLargeOutArgArea_0 DS 0H
+; CHECK: * PPA1 Flags 3
+; CHECK: *   Bit 1: 1 = Argument Area Length is in optional area
+; CHECK:  DC XL1'40'
+; CHECK: * Argument Area Length
+; CHECK:  DC XL4'00000140'
+  %1 = load [33 x i32], ptr @GlobLargeS, align 4
+  call void @fLargeParm([33 x i32] inreg %1)
+  ret void
+}
+
+; === Check that function with parameter does emit PPA1 Length/4 of parms
+define void @fLargeParm([33 x i64] inreg %arr) {
+; CHECK-LABEL: L#EPM_fLargeParm_0 DS 0H
+; CHECK: * Length/4 of Parms
+; CHECK:  DC XL2'0042'
+  %1 = extractvalue [33 x i64] %arr, 1
+  call void @foo(i64 %1)
+  ret void
+}
+
+; === Check that function with alloca call does emit PPA1 Argument Area Length.
+define hidden void @fHasAlloca() {
+; CHECK-LABEL: L#EPM_fHasAlloca_0 DS 0H
+; CHECK: *   Bit 2: 1 = Uses alloca
+; CHECK: fHasAlloca DS 0H
+; CHECK: L#PPA1_fHasAlloca_0 DS 0H
+; CHECK: * PPA1 Flags 3
+; CHECK: *   Bit 1: 1 = Argument Area Length is in optional area
+; CHECK:  DC XL1'40'
+; CHECK: * Argument Area Length
+; CHECK:  DC XL4'00000040'
+  %p = alloca ptr, align 4
+  %1 = load i32, ptr @GlobInt, align 4
+  %2 = alloca i8, i32 %1, align 8
+  store ptr %2, ptr %p, align 4
+  ret void
+}
+
+declare void @foo(i64)

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@redstar redstar merged commit 47efff7 into main Nov 26, 2025
8 of 9 checks passed
@redstar redstar deleted the users/redstar/argarea branch November 26, 2025 21:16
tanji-dg pushed a commit to tanji-dg/llvm-project that referenced this pull request Nov 27, 2025
The Language Environment (LE) reserves 128 byte for the argument area
when the optional field is not present. If the argument area is larger,
then the field must be present to guarantee that the space is reserved
on stack extension. Creating this field when alloca() is used may reduce
the needed stack space in case alloca() causes a stack extension.
GeneraluseAI pushed a commit to GeneraluseAI/llvm-project that referenced this pull request Nov 27, 2025
The Language Environment (LE) reserves 128 byte for the argument area
when the optional field is not present. If the argument area is larger,
then the field must be present to guarantee that the space is reserved
on stack extension. Creating this field when alloca() is used may reduce
the needed stack space in case alloca() causes a stack extension.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants